﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Diagnostics;

namespace KeyboardImageViewer
{
    /// <summary>
    /// Interaction logic for TagAutoCompleteTextBox.xaml
    /// </summary>
    public partial class TagAutoCompleteTextBox : UserControl
    {
        private const int MaxSuggestedTags = 20;
        private bool autoCompleteEnabled = true;

        public TagAutoCompleteTextBox()
        {
            InitializeComponent();
        }

        public Dictionary<string, int> TagsSummary { get; set; }

        public TextBox TextBox
        {
            get
            {
                return this.tags;
            }
        }

        public string Text
        {
            get
            {
                return this.tags.Text;
            }

            set
            {
                this.tags.Text = value;
            }
        }

        public bool AutoCompleteEnabled
        {
            get
            {
                return this.autoCompleteEnabled;
            }

            set
            {
                this.autoCompleteEnabled = value;

                if (!value)
                {
                    this.tagPopup.IsOpen = false;
                }
            }
        }

        public bool LimitToOneTag { get; set; }

        public bool IgnoreDashPrefix { get; set; }

        private void tags_TextChanged(object sender, TextChangedEventArgs e)
        {
            if (!this.autoCompleteEnabled)
            {
                return;
            }

            int caretIndex = this.tags.CaretIndex;

            if (caretIndex == 0 || this.tags.Text[caretIndex - 1] == ' ')
            {
                this.tagPopup.IsOpen = false;
                return;
            }

            List<string> tagsCurrentlyInBox = new List<string>();

            string beforeCaretText = this.tags.Text.Substring(0, caretIndex);
            string[] beforeCaretWords = beforeCaretText.Split(' ');

            if (this.LimitToOneTag && beforeCaretWords.Length > 1)
            {
                this.tagPopup.IsOpen = false;
                return;
            }

            for (int i = 0; i < beforeCaretWords.Length - 1; i++)
            {
                if (beforeCaretWords[i] != string.Empty)
                {
                    tagsCurrentlyInBox.Add(beforeCaretWords[i]);
                }
            }

            string lastWordBeforeCaret = beforeCaretWords[beforeCaretWords.Length - 1].ToLowerInvariant();

            if (lastWordBeforeCaret == string.Empty)
            {
                return;
            }

            if (this.IgnoreDashPrefix)
            {
                if (lastWordBeforeCaret[0] == '-')
                {
                    lastWordBeforeCaret = lastWordBeforeCaret.Substring(1);
                }

                if (lastWordBeforeCaret == string.Empty)
                {
                    return;
                }
            }

            string afterCaretText = this.tags.Text.Substring(caretIndex);
            string[] afterCaretWords = afterCaretText.Split(' ');

            for (int i = 1; i < afterCaretWords.Length; i++)
            {
                if (afterCaretWords[i] != string.Empty)
                {
                    tagsCurrentlyInBox.Add(afterCaretWords[i]);
                }
            }

            List<TagWithFrequency> autoCompleteTags = new List<TagWithFrequency>();

            var sortedTags = from p in this.TagsSummary where p.Key.StartsWith(lastWordBeforeCaret) orderby p.Value descending select p;

            foreach (KeyValuePair<string, int> pair in sortedTags)
            {
                if (!tagsCurrentlyInBox.Contains(pair.Key))
                {
                    autoCompleteTags.Add(new TagWithFrequency { Tag = pair.Key, Frequency = pair.Value });
                }

                if (autoCompleteTags.Count == MaxSuggestedTags)
                {
                    break;
                }
            }

            if (autoCompleteTags.Count == 0)
            {
                this.tagPopup.IsOpen = false;

                return;
            }

            this.tagPopup.IsOpen = true;
            this.tagListBox.ItemsSource = autoCompleteTags;

            this.tagListBox.SelectedIndex = 0;

            Rect textSize = this.tags.GetRectFromCharacterIndex(this.tags.CaretIndex);

            this.tagPopup.PlacementTarget = this.tags;
            this.tagPopup.PlacementRectangle = textSize;
        }

        private void ListItem_MouseDown(object sender, MouseButtonEventArgs e)
        {
            ListBoxItem sendingItem = sender as ListBoxItem;
            TagWithFrequency dataContext = sendingItem.DataContext as TagWithFrequency;

            this.CompleteCurrentTag(dataContext.Tag);
        }

        private void tags_PreviewKeyDown(object sender, KeyEventArgs e)
        {
            switch (e.Key)
            {
                case Key.Up:
                    if (this.tagPopup.IsOpen && this.tagListBox.SelectedIndex > 0)
                    {
                        this.tagListBox.SelectedIndex--;
                    }

                    break;
                case Key.Down:
                    if (this.tagPopup.IsOpen && this.tagListBox.SelectedIndex < this.tagListBox.Items.Count - 1)
                    {
                        this.tagListBox.SelectedIndex++;
                    }

                    break;
                case Key.Tab:
                    if (this.tagPopup.IsOpen)
                    {
                        this.CompleteCurrentTag(((TagWithFrequency)this.tagListBox.SelectedItem).Tag);
                        e.Handled = true;
                    }

                    break;
                default:
                    break;
            }
        }

        private void CompleteCurrentTag(string fullTag)
        {
            int caretIndex = this.tags.CaretIndex;
            string beforeCaretText = this.tags.Text.Substring(0, caretIndex);
            string[] beforeCaretWords = beforeCaretText.Split(' ');
            string lastWordBeforeCaret = beforeCaretWords[beforeCaretWords.Length - 1];
            if (this.IgnoreDashPrefix && lastWordBeforeCaret[0] == '-')
            {
                lastWordBeforeCaret = lastWordBeforeCaret.Substring(1);
            }

            string postSpaceText = this.tags.Text.Substring(caretIndex, this.tags.Text.Length - caretIndex);
            StringBuilder newTag = new StringBuilder();
            newTag.Append(this.tags.Text.Substring(0, caretIndex - lastWordBeforeCaret.Length));
            newTag.Append(fullTag);

            bool addSpace = postSpaceText.Length > 0 || !this.LimitToOneTag;

            if (addSpace)
            {
                newTag.Append(" ");
            }

            newTag.Append(postSpaceText);

            this.tags.Text = newTag.ToString();
            int newCaretIndex = caretIndex - lastWordBeforeCaret.Length + fullTag.Length;
            if (addSpace)
            {
                newCaretIndex++;
            }

            this.tags.CaretIndex = newCaretIndex;

            this.tagPopup.IsOpen = false;
        }

        private void tagPopup_Closed(object sender, EventArgs e)
        {
            this.tags.Focus();
        }
    }
}
